import numpy as np
import pandas as pd
from utils import fea_div, get_data_format
from feature_conf.loan import LoanConfigConstant


def get_real_payoff_time(df):
    """
    payoff_time恢复口径，
    如果截止到回溯日期，账单status=1,-1
    如果截止到回溯日期，账单status=2且回溯时间大于update_time，则update_time为还清时间
    如果截止到回溯日期，账单status=2且回溯时间小于update_time，则当前账单没有还清，则还清时间为-1，所有的还款金额全部归位0
    """
    status = df.status
    sample_time = df.main_apply_time
    payoff_time = df.update_time
    if status == 1:
        return -1
    else:
        if sample_time > payoff_time:
            return payoff_time
        else:
            return -1


def get_real_bill_status(df):
    """
    status恢复逻辑,
    当status=2 且 payoff_time不为None的时候，status=2，说明已出账账单还清了
    当status=2 且 payoff_time为None的时候，status=1，说明账单在回溯时间点之前是没有还清的
    当statue=1时，payoff_time比为None，说明当前账单没有还清
    """
    status = df.status
    payoff_time = df.payoff_time

    if status == 2 and payoff_time != -1:
        return 2
    elif status == 2 and payoff_time == -1:
        return 1
    elif status == 1 and payoff_time == -1:
        return 1


def get_ovd_days(df):
    """
    逾期天数计算逻辑
    如果real_status=2则为还清单，直接用payoff_time-repayment_date，如果为正，则为逾期天数，如果为负则为提前还款天数
    如果real_status=1且未到还款日的，则用户当前在贷款，计算的天数为用户当前在贷款天数
    如果real_status=1且已到还款日的，则用户当前处于逾期状态，计算的天数为用户逾期天数

    """
    import numpy as np

    def get_days_inter(end_time, start_time):
        from datetime import datetime
        end_time = datetime.strptime(end_time, "%Y-%m-%d")
        start_time = datetime.strptime(start_time, "%Y-%m-%d")
        interval = end_time - start_time
        return int(interval.days)

    real_status = df.real_status
    sample_time = df.main_apply_time
    payoff_time = df.payoff_time
    repayment_date = df.repayment_date
    ovd_days = np.nan
    if real_status == 2:
        payoff_time = str(df.payoff_time)[:10]
        repayment_date = str(df.repayment_date)[:10]
        ovd_days = get_days_inter(payoff_time, repayment_date)
    elif real_status == 1 and repayment_date > sample_time:
        ovd_days = np.nan
    elif real_status == 1 and repayment_date < sample_time:
        sample_time = str(df.main_apply_time)[:10]
        repayment_date = str(df.repayment_date)[:10]
        ovd_days = get_days_inter(sample_time, repayment_date)
    return ovd_days


def extract_order_features(df, time_col, time_inter, version='{version}', country_id='mx'):
    """

    Args:
        df: the data frame that contain order data
        time_col: date_inter, loan_rank, mth_inter
        time_inter:
        country_id:[mx, cl, co]
        version: feature version

    Returns:

    """
    time_flag = ''
    if time_col == 'date_inter':
        time_flag = 'd'
    elif time_col == 'loan_rank':
        time_flag = 'r'
    elif time_col == 'mth_inter':
        time_flag = 'm'

    order_fea_list = []
    order_fea_name_list = []
    # 全部订单（拒绝+成功）
    tmp_df = df[df[time_col] <= time_inter]
    pass_tmp_df = tmp_df[tmp_df.status == 21]
    rej_tmp_df = tmp_df[tmp_df.status == 22]
    # 订单数量类特征
    order_num = tmp_df.shape[0]  # 总订单数量
    pass_order_num = pass_tmp_df.shape[0]  # 通过订单数量
    rej_order_num = rej_tmp_df.shape[0]  # 拒绝订单数量
    pass_order_rate = fea_div(pass_order_num, order_num)  # 订单通过率
    rej_order_rate = fea_div(rej_order_num, order_num)  # 订单拒绝率
    # 金额类特征
    max_loan_amount = get_data_format(tmp_df.loan_amount.max())  # 申请金额最大值
    min_loan_amount = get_data_format(tmp_df.loan_amount.min())  # 申请金额最小值
    sum_loan_amount = tmp_df.loan_amount.sum()  # 申请金额和
    avg_loan_amount = get_data_format(round(tmp_df.loan_amount.mean(), 4))  # 申请金额平均值
    std_loan_amount = get_data_format(round(tmp_df.loan_amount.std(), 4), sub_type='1')  # 申请金额标准差
    pass_max_loan_amount = get_data_format(pass_tmp_df.loan_amount.max())  # 通过金额最大值
    pass_min_loan_amount = get_data_format(pass_tmp_df.loan_amount.min())  # 通过金额最小值
    pass_sum_loan_amount = pass_tmp_df.loan_amount.sum()  # 通过金额和
    pass_avg_loan_amount = get_data_format(round(pass_tmp_df.loan_amount.mean(), 4))  # 通过金额平均值
    pass_std_loan_amount = get_data_format(round(pass_tmp_df.loan_amount.std(), 4), sub_type='1')  # 通过金额标准差
    rej_max_loan_amount = get_data_format(rej_tmp_df.loan_amount.max())  # 拒绝金额最大值
    rej_min_loan_amount = get_data_format(rej_tmp_df.loan_amount.min())  # 拒绝金额最小值
    rej_sum_loan_amount = rej_tmp_df.loan_amount.sum()  # 拒绝金额和
    rej_avg_loan_amount = get_data_format(round(rej_tmp_df.loan_amount.mean(), 4))  # 拒绝金额平均值
    rej_std_loan_amount = get_data_format(round(rej_tmp_df.loan_amount.std(), 4), sub_type='1')  # 拒绝金额标准差
    pass_loan_amount_rate = fea_div(pass_sum_loan_amount, sum_loan_amount)  # 金额通过率
    rej_sum_loan_amount_rate = fea_div(rej_sum_loan_amount, sum_loan_amount)  # 金额拒绝率
    # 订单间隔类特征
    max_loan_day_inter = get_data_format(tmp_df.time_diff.max())  # 申请间隔最大值
    min_loan_day_inter = get_data_format(tmp_df.time_diff.min())  # 申请间隔最小值
    sum_loan_day_inter = int(tmp_df.time_diff.sum())  # 申请间隔和
    avg_loan_day_inter = get_data_format(round(tmp_df.time_diff.mean(), 4))  # 申请间隔平均值
    std_loan_day_inter = get_data_format(round(tmp_df.time_diff.std(), 4), sub_type='1')  # 申请间隔标准差
    order_fea_name_list.extend([f'loan_{country_id}_order_num_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_pass_order_num_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_rej_order_num_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_pass_order_rate_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_rej_order_rate_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_max_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_min_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_sum_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_avg_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_std_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_pass_max_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_pass_min_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_pass_sum_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_pass_avg_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_pass_std_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_rej_max_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_rej_min_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_rej_sum_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_rej_avg_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_rej_std_loan_amount_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_pass_loan_amount_rate_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_rej_sum_loan_amount_rate_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_max_loan_day_inter_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_min_loan_day_inter_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_sum_loan_day_inter_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_avg_loan_day_inter_{version}_{time_inter}{time_flag}',
                                f'loan_{country_id}_std_loan_day_inter_{version}_{time_inter}{time_flag}', ])

    order_fea_list.extend([order_num,
                           pass_order_num,
                           rej_order_num,
                           pass_order_rate,
                           rej_order_rate,
                           max_loan_amount,
                           min_loan_amount,
                           sum_loan_amount,
                           avg_loan_amount,
                           std_loan_amount,
                           pass_max_loan_amount,
                           pass_min_loan_amount,
                           pass_sum_loan_amount,
                           pass_avg_loan_amount,
                           pass_std_loan_amount,
                           rej_max_loan_amount,
                           rej_min_loan_amount,
                           rej_sum_loan_amount,
                           rej_avg_loan_amount,
                           rej_std_loan_amount,
                           pass_loan_amount_rate,
                           rej_sum_loan_amount_rate,
                           max_loan_day_inter,
                           min_loan_day_inter,
                           sum_loan_day_inter,
                           avg_loan_day_inter,
                           std_loan_day_inter, ])

    order_fea_dict = dict(zip(order_fea_name_list, order_fea_list))
    return order_fea_dict


def extract_bill_normal_features(cate_df,
                                 normal_df,
                                 time_col='day_inter',
                                 time_inter=None,
                                 feature_type='ontime',
                                 country_id='mx',
                                 version='v1'):
    """

    Args:
        cate_df: onloan, outstanding, ontime, pre, ovd
        normal_df: normal bill, remove extension bill
        time_col:day_inter just for bill features
        feature_type: ['ovd', 'pre', 'ontime', 'outstanding', 'onloan']
        country_id: [mx, cl, co]
        time_inter:
        version: feature version

    Returns:

    """
    if feature_type not in ['ovd', 'pre', 'ontime', 'outstanding', 'onloan']:
        raise ValueError("feature_type error, the value in ['ovd', 'pre', 'ontime', 'outstanding', 'onloan']")
    bill_amt_cate = LoanConfigConstant.BILL_AMOUNT[feature_type]

    bill_fea_list = []
    bill_fea_name_list = []
    tmp_normal_installment_df = normal_df[normal_df[time_col] <= time_inter]
    tmp_cate_df = cate_df[cate_df[time_col] <= time_inter]

    loan_num = tmp_cate_df.shape[0]
    loan_rate = fea_div(loan_num, tmp_normal_installment_df.shape[0])

    loan_amt_sum = tmp_cate_df[bill_amt_cate].sum()
    loan_amt_max = get_data_format(tmp_cate_df[bill_amt_cate].max())
    loan_amt_min = get_data_format(tmp_cate_df[bill_amt_cate].min())
    loan_amt_avg = get_data_format(round(tmp_cate_df[bill_amt_cate].mean(), 4))
    loan_amt_std = get_data_format(round(tmp_cate_df[bill_amt_cate].std(), 4), sub_type='1')

    loan_prcp_sum = tmp_cate_df.principal.sum()
    loan_prcp_max = get_data_format(tmp_cate_df.principal.max())
    loan_prcp_min = get_data_format(tmp_cate_df.principal.min())
    loan_prcp_avg = get_data_format(round(tmp_cate_df.principal.mean(), 4))
    loan_prcp_std = get_data_format(round(tmp_cate_df.principal.std(), 4), sub_type='1')

    loan_itr_sum = tmp_cate_df.interest.sum()
    loan_itr_max = get_data_format(tmp_cate_df.interest.max())
    loan_itr_min = get_data_format(tmp_cate_df.interest.min())
    loan_itr_avg = get_data_format(round(tmp_cate_df.interest.mean(), 4))
    loan_itr_std = get_data_format(round(tmp_cate_df.interest.std(), 4), sub_type='1')

    loan_cut_itr_sum = tmp_cate_df.cut_interest.sum()
    loan_cut_itr_max = get_data_format(tmp_cate_df.cut_interest.max())
    loan_cut_itr_min = get_data_format(tmp_cate_df.cut_interest.min())
    loan_cut_itr_avg = get_data_format(round(tmp_cate_df.cut_interest.mean(), 4))
    loan_cut_itr_std = get_data_format(round(tmp_cate_df.cut_interest.std(), 4), sub_type='1')

    bill_fea_list.extend([loan_num,
                          loan_rate,
                          loan_amt_sum,
                          loan_amt_max,
                          loan_amt_min,
                          loan_amt_avg,
                          loan_amt_std,
                          loan_prcp_sum,
                          loan_prcp_max,
                          loan_prcp_min,
                          loan_prcp_avg,
                          loan_prcp_std,
                          loan_itr_sum,
                          loan_itr_max,
                          loan_itr_min,
                          loan_itr_avg,
                          loan_itr_std,
                          loan_cut_itr_sum,
                          loan_cut_itr_max,
                          loan_cut_itr_min,
                          loan_cut_itr_avg,
                          loan_cut_itr_std, ])
    fea_desc = ''
    if feature_type == 'ovd':
        fea_desc = 'ovd'

    bill_fea_name_list.extend([f'loan_{country_id}_{feature_type}_loan_num_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_rate_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_{fea_desc}amt_sum_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_{fea_desc}amt_max_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_{fea_desc}amt_min_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_{fea_desc}amt_avg_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_{fea_desc}amt_std_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_prcp_sum_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_prcp_max_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_prcp_min_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_prcp_avg_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_prcp_std_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_itr_sum_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_itr_max_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_itr_min_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_itr_avg_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_itr_std_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_cut_itr_sum_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_cut_itr_max_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_cut_itr_min_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_cut_itr_avg_{version}_{time_inter}d',
                               f'loan_{country_id}_{feature_type}_loan_cut_itr_std_{version}_{time_inter}d', ])

    bill_fea_dict = dict(zip(bill_fea_name_list, bill_fea_list))
    return bill_fea_dict


def extract_bill_status_features(cate_df,
                                 normal_df,
                                 time_col='day_inter',
                                 sub_time_col='pre_days',
                                 time_inter=None,
                                 feature_type='ovd',
                                 country_id='mx',
                                 version='v1'):
    """

    Args:
        cate_df: [ovd_df, pre_df]
        normal_df: normal_df
        time_col: day_inter
        sub_time_col: ['ovd_days', 'pre_days']
        time_inter:
        feature_type: [ovd, pre]
        country_id: 'mx'
        version: v1

    Returns:

    """
    bill_status_fea_list = []
    bill_status_fea_name_list = []
    amt_cate = LoanConfigConstant.BILL_AMOUNT[feature_type]
    tmp_normal_installment_df = normal_df[normal_df[time_col] <= time_inter]
    tmp_ovd_df = cate_df[cate_df[time_col] <= time_inter]
    ovd_loan_num = tmp_ovd_df.shape[0]

    for od in LoanConfigConstant.BILL_OVD_DAYS_LIST:
        ovd_le_loan_num = tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].shape[0]
        ovd_le_loan_rate = fea_div(ovd_le_loan_num, ovd_loan_num)
        ovd_le_loan_all_rate = fea_div(ovd_le_loan_num, tmp_normal_installment_df.shape[0])

        ovd_le_loan_ovdamt_sum = tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od][amt_cate].sum()
        ovd_le_loan_ovdamt_max = get_data_format(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od][amt_cate].max())
        ovd_le_loan_ovdamt_min = get_data_format(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od][amt_cate].min())
        ovd_le_loan_ovdamt_avg = get_data_format(round(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od][amt_cate].mean(), 4))
        ovd_le_loan_ovdamt_std = get_data_format(round(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od][amt_cate].std(), 4),
                                                 sub_type='1')

        ovd_le_loan_prcp_sum = tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].principal.sum()
        ovd_le_loan_prcp_max = get_data_format(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].principal.max())
        ovd_le_loan_prcp_min = get_data_format(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].principal.min())
        ovd_le_loan_prcp_avg = get_data_format(round(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].principal.mean(), 4))
        ovd_le_loan_prcp_std = get_data_format(round(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].principal.std(), 4),
                                               sub_type='1')

        ovd_le_loan_itr_sum = tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].interest.sum()
        ovd_le_loan_itr_max = get_data_format(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].interest.max())
        ovd_le_loan_itr_min = get_data_format(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].interest.min())
        ovd_le_loan_itr_avg = get_data_format(round(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].interest.mean(), 4))
        ovd_le_loan_itr_std = get_data_format(round(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].interest.std(), 4),
                                              sub_type='1')

        ovd_le_loan_cut_itr_sum = tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].cut_interest.sum()
        ovd_le_loan_cut_itr_max = get_data_format(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].cut_interest.max())
        ovd_le_loan_cut_itr_min = get_data_format(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].cut_interest.min())
        ovd_le_loan_cut_itr_avg = get_data_format(
            round(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].cut_interest.mean(), 4))
        ovd_le_loan_cut_itr_std = get_data_format(
            round(tmp_ovd_df[tmp_ovd_df[sub_time_col] <= od].cut_interest.std(), 4), sub_type='1')

        bill_status_fea_list.extend([ovd_le_loan_num,
                                     ovd_le_loan_rate,
                                     ovd_le_loan_all_rate,
                                     ovd_le_loan_ovdamt_sum,
                                     ovd_le_loan_ovdamt_max,
                                     ovd_le_loan_ovdamt_min,
                                     ovd_le_loan_ovdamt_avg,
                                     ovd_le_loan_ovdamt_std,
                                     ovd_le_loan_prcp_sum,
                                     ovd_le_loan_prcp_max,
                                     ovd_le_loan_prcp_min,
                                     ovd_le_loan_prcp_avg,
                                     ovd_le_loan_prcp_std,
                                     ovd_le_loan_itr_sum,
                                     ovd_le_loan_itr_max,
                                     ovd_le_loan_itr_min,
                                     ovd_le_loan_itr_avg,
                                     ovd_le_loan_itr_std,
                                     ovd_le_loan_cut_itr_sum,
                                     ovd_le_loan_cut_itr_max,
                                     ovd_le_loan_cut_itr_min,
                                     ovd_le_loan_cut_itr_avg,
                                     ovd_le_loan_cut_itr_std, ])
        fea_desc = ''
        if feature_type == 'ovd':
            fea_desc = 'ovd'

        bill_status_fea_name_list.extend([f'loan_{country_id}_{feature_type}_le{od}d_loan_num_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_rate_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_all_rate_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_{fea_desc}amt_sum_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_{fea_desc}amt_max_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_{fea_desc}amt_min_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_{fea_desc}amt_avg_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_{fea_desc}amt_std_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_prcp_sum_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_prcp_max_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_prcp_min_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_prcp_avg_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_prcp_std_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_itr_sum_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_itr_max_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_itr_min_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_itr_avg_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_itr_std_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_cut_itr_sum_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_cut_itr_max_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_cut_itr_min_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_cut_itr_avg_v1_{time_inter}d',
                                          f'loan_{country_id}_{feature_type}_le{od}d_loan_cut_itr_std_v1_{time_inter}d'])
    bill_status_fea_dict = dict(zip(bill_status_fea_name_list, bill_status_fea_list))
    return bill_status_fea_dict


def extract_bill_extension_features(cate_df,
                                    normal_df,
                                    time_col='day_inter',
                                    time_inter=None,
                                    feature_type='extension',
                                    country_id='mx',
                                    version='v1'):
    """

    Args:
        cate_df:extension_df
        normal_df:normal_df
        time_col:day_inter
        time_inter:
        feature_type:extension
        country_id:[mx, cl, co]
        version:v1

    Returns:

    """

    extension_features_list = []
    extension_features_name_list = []
    tmp_extension_df = cate_df[cate_df[time_col] <= time_inter]
    extension_loan_num = tmp_extension_df.shape[0]
    extension_loan_rate = fea_div(extension_loan_num, normal_df.shape[0])
    extension_fee_sum = tmp_extension_df.extension_fee.sum()
    extension_fee_max = get_data_format(tmp_extension_df.extension_fee.max())
    extension_fee_min = get_data_format(tmp_extension_df.extension_fee.min())
    extension_fee_avg = get_data_format(round(tmp_extension_df.extension_fee.mean(), 4))
    extension_fee_std = get_data_format(round(tmp_extension_df.extension_fee.std(), 4), sub_type='1')

    extension_features_list.extend([extension_loan_num,
                                    extension_loan_rate,
                                    extension_fee_sum,
                                    extension_fee_max,
                                    extension_fee_min,
                                    extension_fee_avg,
                                    extension_fee_std])

    extension_features_name_list.extend([f'loan_{country_id}_extension_loan_num_{version}_{time_inter}d',
                                         f'loan_{country_id}_extension_loan_rate_{version}_{time_inter}d',
                                         f'loan_{country_id}_extension_fee_sum_{version}_{time_inter}d',
                                         f'loan_{country_id}_extension_fee_max_{version}_{time_inter}d',
                                         f'loan_{country_id}_extension_fee_min_{version}_{time_inter}d',
                                         f'loan_{country_id}_extension_fee_avg_{version}_{time_inter}d',
                                         f'loan_{country_id}_extension_fee_std_{version}_{time_inter}d'])

    bill_fea_dict = dict(zip(extension_features_name_list, extension_features_list))
    return bill_fea_dict


def preprocess_data(apply_time, order_data, loan_data):
    apply_time = apply_time
    # order data format
    order_data = order_data
    installment_data = loan_data
    order_data['main_apply_time'] = pd.to_datetime(apply_time)
    order_data['apply_time'] = pd.to_datetime(order_data['apply_time'])
    order_data['create_time'] = pd.to_datetime(order_data['create_time'])
    order_data['update_time'] = pd.to_datetime(order_data['update_time'])
    order_data['date_inter'] = (order_data['main_apply_time'] - order_data['apply_time']).dt.days
    order_data = order_data[
        (order_data.main_apply_time > order_data.apply_time) & (order_data.date_inter <= 360) & (
            order_data.status.isin([21, 22]))]
    order_data['loan_rank'] = order_data.groupby(['user_id', 'main_apply_time'])['app_order_id'].rank(
        method='first', ascending=False)
    order_data = order_data.sort_values(['apply_time', 'app_order_id'], ascending=[True, True])
    order_data['time_diff'] = order_data.groupby(['user_id', 'main_apply_time'])['apply_time'].diff().dt.days
    order_data['mth_inter'] = (order_data['date_inter'] / 30).astype(int) + 1

    # installment data format

    installment_data['main_apply_time'] = pd.to_datetime(apply_time)
    installment_data['create_time'] = pd.to_datetime(installment_data['create_time'])
    installment_data['update_time'] = pd.to_datetime(installment_data['update_time'])
    installment_data = installment_data[
        (installment_data.status.isin([1, 2])) & (installment_data.main_apply_time > installment_data.create_time)]
    installment_data['repayment_date'] = pd.to_datetime(installment_data.repayment_date)
    installment_data['day_inter'] = (installment_data.main_apply_time - installment_data.create_time).dt.days
    installment_data['payoff_time'] = installment_data.apply(get_real_payoff_time, axis=1)
    installment_data['real_status'] = installment_data.apply(get_real_bill_status, axis=1)
    installment_data['ovd_days'] = installment_data.apply(get_ovd_days, axis=1)
    installment_data['repaid_principal'] = np.where(
        (installment_data.real_status == 1) & (installment_data.main_apply_time > installment_data.repayment_date),
        0, installment_data['repaid_principal'])
    installment_data['repaid_interest'] = np.where(
        (installment_data.real_status == 1) & (installment_data.main_apply_time > installment_data.repayment_date),
        0, installment_data['repaid_interest'])
    installment_data['repaid_cut_interest'] = np.where(
        (installment_data.real_status == 1) & (installment_data.main_apply_time > installment_data.repayment_date),
        0, installment_data['repaid_cut_interest'])
    installment_data['repaid_service_fee'] = np.where(
        (installment_data.real_status == 1) & (installment_data.main_apply_time > installment_data.repayment_date),
        0, installment_data['repaid_service_fee'])
    installment_data['repaid_management_fee'] = np.where(
        (installment_data.real_status == 1) & (installment_data.main_apply_time > installment_data.repayment_date),
        0, installment_data['repaid_management_fee'])
    installment_data['repaid_overdue_interest'] = np.where(
        (installment_data.real_status == 1) & (installment_data.main_apply_time > installment_data.repayment_date),
        0, installment_data['repaid_overdue_interest'])
    installment_data['repaid_penalty'] = np.where(
        (installment_data.real_status == 1) & (installment_data.main_apply_time > installment_data.repayment_date),
        0, installment_data['repaid_penalty'])

    installment_data['all_repaid_amt'] = installment_data['repaid_principal'] + \
                                         installment_data['repaid_interest'] + \
                                         installment_data['repaid_cut_interest'] + \
                                         installment_data['repaid_service_fee'] + \
                                         installment_data['repaid_management_fee'] + \
                                         installment_data['repaid_overdue_interest'] + \
                                         installment_data['repaid_penalty'] + \
                                         installment_data['discount_amount']

    installment_data['all_due_amt'] = installment_data['principal'] + \
                                      installment_data['interest'] + \
                                      installment_data['cut_interest'] + \
                                      installment_data['service_fee'] + \
                                      installment_data['management_fee'] + \
                                      installment_data['penalty']
    installment_data['ovd_amt'] = abs(
        installment_data['all_repaid_amt'] - installment_data['all_due_amt'])

    # normal order
    # todo bugfix 数据穿越问题，installment_data数据恢复有问题
    normal_installment_df = installment_data[
        installment_data.settlement_type.isin([0, 1])]
    # extension order
    # todo bugfix 数据穿越问题，installment_data数据恢复有问题
    extension_installment_df = installment_data[installment_data.settlement_type == 2]

    ovd_repay_df = normal_installment_df[
        (normal_installment_df.real_status == 2) & (normal_installment_df.ovd_days > 0)]

    pre_repay_df = normal_installment_df[
        (normal_installment_df.real_status == 2) & (normal_installment_df.ovd_days < 0)]
    pre_repay_df['pre_days'] = abs(pre_repay_df.ovd_days)
    pre_repay_df['pre_amt'] = pre_repay_df.all_repaid_amt

    ontime_repay_df = normal_installment_df[
        (normal_installment_df.real_status == 2) & (normal_installment_df.ovd_days == 0)]

    outstanding_repay_df = normal_installment_df[
        (normal_installment_df.real_status == 1) & (normal_installment_df.ovd_days >= 0)]

    onloan_repay_df = normal_installment_df[
        (normal_installment_df.real_status == 1) & (normal_installment_df.ovd_days.isnull())]

    return {'order_df': order_data,
            'normal_installment_df': normal_installment_df,
            'ovd_repay_df': ovd_repay_df,
            'pre_repay_df': pre_repay_df,
            'ontime_repay_df': ontime_repay_df,
            'outstanding_repay_df': outstanding_repay_df,
            'onloan_repay_df': onloan_repay_df,
            'extension_repay_df': extension_installment_df
            }
